package com.imooc.miaosha.rabbitmq;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.HeadersExchange;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import org.springframework.amqp.core.Queue;

import java.util.HashMap;
import java.util.Map;

/**
 * @author liyuhui
 * 最新版本的RabbitMQ有四种交换机类型，分别是Direct exchange、Fanout exchange、Topic exchange、Headers exchange。
 */
@Configuration
public class MQConfig {

    public static final String MIAOSHA_QUEUE = "miaosha.queue";
    public static final String QUEUE = "queue";
    public static final String QUEUE1 = "queue1";
    public static final String QUEUE2 = "queue2";
    public static final String HEADERS_QUEUE = "headers.queue";
    public static final String DIRECT_EXCHANGE = "directExchage";
    public static final String TOPIC_EXCHANGE = "topicExchage";
    public static final String FANOUT_EXCHANGE = "fanoutxchage";
    public static final String HEADERS_EXCHANGE = "headersExchage";

    /**
     * queue
     * */
    @Bean
    public Queue miaoshaQueue() {
        return new Queue(MIAOSHA_QUEUE, true);
    }

    @Bean
    public Queue queue() {
        return new Queue(QUEUE, true);
    }

    @Bean
    public Queue queue1() {
        return new Queue(QUEUE1, true);
    }

    @Bean
    public Queue queue2() {
        return new Queue(QUEUE2, true);
    }

    @Bean
    public Queue headersQueue1() {
        return new Queue(HEADERS_QUEUE, true);
    }



    /**
     * direct模式
     * 一个队列会和一个交换机绑定，除此之外再绑定一个routing_key。
     */
    @Bean
    public DirectExchange directExchange(){
        return new DirectExchange(DIRECT_EXCHANGE);
    }

    @Bean
    public Binding topicBinding() {
        return BindingBuilder.bind(queue()).to(directExchange()).with("key");
    }

    /**
     * Topic模式 交换机Exchange
     * 先放入交换机中，通过with里参数筛选后再放入queue中。
     * 直连交换机的routing_key方案非常简单，如果我们希望一条消息发送给多个队列，
     * 那么这个交换机需要绑定上非常多的routing_key，
     * 假设每个交换机上都绑定一堆的routing_key连接到各个队列上。那么消息的管理就会异常地困难。
     * 所以RabbitMQ提供了一种主题交换机，发送到主题交换机上的消息需要携带指定规则的routing_key，
     * 主题交换机会根据这个规则将数据发送到对应的(多个)队列上。
     * */
    @Bean
    public TopicExchange topicExchange(){
        return new TopicExchange(TOPIC_EXCHANGE);
    }

    @Bean
    public Binding topicBinding1() {
        return BindingBuilder.bind(queue1()).to(topicExchange()).with("topic.key1");
    }

    @Bean
    public Binding topicBinding2() {
        return BindingBuilder.bind(queue2()).to(topicExchange()).with("topic.#");
    }

    /**
     * Fanout模式 交换机Exchange
     * 先放入交换机中，不需要通过筛选，所有绑定的queue都能接收到。
     * */
    @Bean
    public FanoutExchange fanoutExchange(){
        return new FanoutExchange(FANOUT_EXCHANGE);
    }
    @Bean
    public Binding FanoutBinding1() {
        return BindingBuilder.bind(queue1()).to(fanoutExchange());
    }
    @Bean
    public Binding FanoutBinding2() {
        return BindingBuilder.bind(queue2()).to(fanoutExchange());
    }

    /**
     * Header模式 交换机Exchange
     * 首部交换机是忽略routing_key的一种路由方式。
     * 路由器和交换机路由的规则是通过Headers信息来交换的，这个有点像HTTP的Headers。
     * 将一个交换机声明成首部交换机，绑定一个队列的时候，定义一个Hash的数据结构，
     * 消息发送的时候，会携带一组hash数据结构的信息，当Hash的内容匹配上的时候，消息就会被写入队列。
     * 绑定交换机和队列的时候，Hash结构中要求携带一个键“x-match”，这个键的Value可以是any或者all，
     * 这代表消息携带的Hash是需要全部匹配(all)，还是仅匹配一个键(any)就可以了。
     * 相比直连交换机，首部交换机的优势是匹配的规则不被限定为字符串(string)。
     * */
    @Bean
    public HeadersExchange headersExchange(){
        return new HeadersExchange(HEADERS_EXCHANGE);
    }

    @Bean
    public Binding headersBinding() {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("header1", "value1");
        map.put("header2", "value2");
        //whereAll,whereAny,whereOne等等，有许多条件，含义参看文档
        return BindingBuilder.bind(headersQueue1()).to(headersExchange()).whereAll(map).match();
    }
}
